package com.ling.plasticene.pattern;

import android.support.annotation.NonNull;

import com.ling.plasticene.BuildConfig;
import com.ling.plasticene.common.Stateable;
import com.ling.plasticene.recyclerview.loadmore.LoadMore;
import com.ling.plasticene.vary.VaryHelper;

import java.util.ArrayList;
import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;


/**
 * Function：简化下拉刷新，上拉加载更多事件监听及控件状态同步
 * Created by ling(quan.ling@hotmail.com) on 15/11/12.
 */
public class PagedVaryLoader<T> implements LoadMore.OnLoadMoreListener {
    public static final int START_PAGE = 1;

    public interface Provider<T> {
        Call<T> getCall(int page);

        /**
         * 处理请求结果
         * 如果发生错误需抛出异常,否则不会处理错误状态
         *
         * @param page
         * @param result
         * @return
         * @throws Exception
         */
        int processResult(int page, @NonNull T result) throws Exception;
    }

    private Provider<T> mProvider;
    private List<LoaderCallBack> mCallBackList = new ArrayList<>();

    private LoadMore mLoadMore;
    private VaryHelper mVaryHelper;

    private int mCurPage = 0;
    private boolean isLoading;
    private boolean isException = true;

    /**
     * 不同状态显示不同页面
     *
     * @param provider
     * @param VaryHelper
     */
    public PagedVaryLoader(Provider<T> provider, VaryHelper VaryHelper) {
        mProvider = provider;
        mVaryHelper = VaryHelper;
    }

    /**
     * 分页加载 + 不同状态显示不同页面
     *
     * @param provider
     * @param loadMore
     * @param VaryHelper
     */
    public PagedVaryLoader(Provider<T> provider, LoadMore loadMore, VaryHelper VaryHelper) {
        mProvider = provider;
        mLoadMore = loadMore;
        mVaryHelper = VaryHelper;

        mLoadMore.setLoadMoreListener(this);
    }

    public void addLoaderCallBack(LoaderCallBack callBack) {
        if (mCallBackList == null) {
            mCallBackList = new ArrayList<>();
        }
        mCallBackList.add(callBack);
    }

    public void refresh() {
        loadInternal(START_PAGE);
    }

    public void load() {
        if (isException) {
            loadInternal(START_PAGE);
        }
    }

    @Override
    public void onLoadMore() {
        if (isLoading) return;
        loadInternal(mCurPage + 1);
    }

    private void loadInternal(final int startPage) {
        dispatchStartLoading(startPage);
        mProvider.getCall(startPage).enqueue(new Callback<T>() {
            @Override
            public void onResponse(Call<T> call, Response<T> response) {
                processResult(startPage, response);
            }

            @Override
            public void onFailure(Call<T> call, Throwable t) {
                if (BuildConfig.DEBUG) {
                    t.printStackTrace();
                }
                dispatchLoadError(startPage, t.getMessage());
            }
        });
    }

    protected void processResult(int page, Response<T> response) {
        if (response.body() == null || response.body() == null) {
            dispatchLoadError(page, "数据加载失败,返回为空!");
        }

        try {
            int state = mProvider.processResult(page, response.body());
            if (state == Stateable.NORMAL || state == Stateable.EMPTY) {
                dispatchLoadSuccess(page, state);
            }
        } catch (Exception e) {
//            if (BuildConfig.DEBUG) {
                e.printStackTrace();
//            }

            dispatchLoadError(page, e.getMessage());
        }
    }

    protected void dispatchStartLoading(int curPage) {
        if (curPage == START_PAGE) {
            mVaryHelper.setState(Stateable.LOADING);
        } else {
            mLoadMore.setState(Stateable.LOADING);
        }

        for (LoaderCallBack callBack : mCallBackList) {
            callBack.onStartLoading(curPage);
        }
    }

    protected void dispatchLoadError(int curPage, String error) {
        if (curPage == START_PAGE) {
            isException = true;

            mVaryHelper.setState(Stateable.ERROR);
        } else {
            mLoadMore.setState(Stateable.ERROR);
        }

        for (LoaderCallBack callBack : mCallBackList) {
            callBack.onLoadFailure(curPage, error);
        }
    }

    protected void dispatchLoadSuccess(int curPage, int state) {
        if (curPage == START_PAGE) {
            isException = false;

            mVaryHelper.setState(state);
            if (mLoadMore != null) {
                mLoadMore.setState(Stateable.NORMAL);
            }
        } else {
            mLoadMore.setState(state);
        }

        for (LoaderCallBack callBack : mCallBackList) {
            callBack.onLoadComplete(curPage, state);
        }

        mCurPage = curPage;
    }
}
